/*
 * Copyright (C) 2011 TargetBoard
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jaxb;


import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

import jaxb.generated.book.Book;
import jaxb.generated.book.History;
import jaxb.generated.book.Record;
import jaxb.generated.datatable.Table;
import jaxb.generated.users.Users;

/**
 * @author amc
 *
 */
public class XmlManager{
	public static final int MAX_HISTORY_SIZE = 10;
	private XmlExtractor<Table> tableExtractor;
	private XmlExtractor<Book> bookExtractor;
	private XmlExtractor<Users> usersExtractor;

	private XmlInjector<Book> bookInjector;
	private Book book;
	private Table table;
	private Users users;
	private boolean initialized = false;
	private static XmlManager instance;

	public synchronized void init(String dataTablePath, String usersPath, String bookPath) throws InitailizedException {
		if (initialized) {
			throw new InitailizedException("The XmlManagre was already initialized.");
		}
		tableExtractor = new XmlExtractor<Table>(dataTablePath);
		bookExtractor = new XmlExtractor<Book>(bookPath);
		usersExtractor = new XmlExtractor<Users>(usersPath);
		bookInjector = new XmlInjector<Book>(bookPath);
		initialized = true;

	}

	private XmlManager() {
	}

	public static synchronized XmlManager getInstance() {
		if (instance == null) {
			instance = new XmlManager();
		}
		return instance;
	}

	public synchronized void resetData(){
		book=null;
		table=null;
		users=null;
	}
	
	public synchronized Table getTable() throws InitailizedException {
		if (!initialized) {
			throw new InitailizedException("The XmlManagre was not initialized.");
		}
		if (table == null) {
			table = tableExtractor.extract();
		}
		return table;
	}

	public synchronized void setBook(String user, String[] keys) throws InitailizedException {
		if (!initialized) {
			throw new InitailizedException("The XmlManagre was not initialized.");
		}
		List<Record> recordList = new ArrayList<Record>();
		Map<String, Record> recordMap = new HashMap<String, Record>();
		for (Record rec : getBook().getRecord()) {
			recordMap.put(rec.getKey(), rec);
		}
		for (String key : keys) {
			if (recordMap.containsKey(key)) {
				updateRecord(user, recordMap.get(key));
			} else {
				addRecord(user, key, recordList);
			}
		}
		book.getRecord().addAll(recordList);
		bookInjector.inject(new jaxb.generated.book.ObjectFactory().createBook(book));
	}

	private void addRecord(String user, String key, List<Record> record) {
		if (user != null) {
			Record rec = new jaxb.generated.book.ObjectFactory().createRecord();
			rec.setKey(key);
			rec.setUser(user);
			rec.setBookDate(getDate());
			record.add(rec);
		}
	}

	private void updateRecord(String user, Record rec) {
		String oldUser = rec.getUser();
		XMLGregorianCalendar oldDate = rec.getBookDate();
		rec.setUser(user);
		if (user == null) {
			rec.setBookDate(null);
		} else {
			rec.setBookDate(getDate());
		}
		if (oldUser != null) {
			updateHistory(oldUser, oldDate, rec.getHistory());
		}
	}

	private XMLGregorianCalendar getDate() {
		DatatypeFactory datatypes;
		XMLGregorianCalendar date = null;
		try {
			datatypes = DatatypeFactory.newInstance();
			date = datatypes.newXMLGregorianCalendar((GregorianCalendar) GregorianCalendar.getInstance());
		} catch (DatatypeConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return date;
	}

	private void updateHistory(String oldUser, XMLGregorianCalendar oldDate, List<History> historyList) {
		if (historyList.size() > MAX_HISTORY_SIZE) {
			historyList.remove(0);
		}
		History history = new jaxb.generated.book.ObjectFactory().createHistory();
		history.setBookDate(oldDate);
		history.setUser(oldUser);
		historyList.add(history);
	}

	public synchronized Book getBook() throws InitailizedException {
		if (!initialized) {
			throw new InitailizedException("The XmlManagre was not initialized.");
		}
		if (book == null) {
			book = bookExtractor.extract();
		}
		return book;
	}

	public synchronized Users getUsers() throws InitailizedException {
		if (!initialized) {
			throw new InitailizedException("The XmlManagre was not initialized.");
		}
		if (users == null) {
			users = usersExtractor.extract();
		}
		return users;
	}
}
